#ifndef BASEUNIT_H
#define BASEUNIT_H

#include "Vector2df.h"
#include "AnimatedSprite.h"
#include "CountDown.h"

#include "MapData.h"
#include "CollisionObject.h"
#include "SpawnUnitData.h"

//----------------------------
// by foxblock for Wandor - Oct 14 2009
// Base unit class, you cannot create this directly use an inheritance instead
//----------------------------
class Level;

// Class sturcts
enum UNIT_STATES
{
    usNONE=-1,
    usNORMAL,
    usVULNERABLE,
    usPICKUPABLE,
    usPROJECTILE
};
enum HERO_STATES
{
    hsNORMAL,
    hsATTACKING,
    hsPOUNDING,
    hsDUCKED,
    hsCHARGING,
    hsCARRYING,
    hsRUNNING,
    hsRUNATTACKING
};

class BaseUnit
{
public:

    BaseUnit();
    BaseUnit(const Vector2df p, const Vector2df v);
    virtual ~BaseUnit()=0;

    // getters
    virtual int getDirection() const {return m_direction;}
    virtual int getHeight() const;
    virtual int getWidth() const;
    virtual Vector2df getPosition(bool inTiles=false) const;
    virtual Vector2df getScreenPosition() const;
    virtual Vector2df getSize() const;
    virtual Vector2df getSpeed() const;
    virtual int getState() const {return m_state;};
    Level *getLevel() const {return m_level;}
    SpawnUnitData* getSpawnData() const {return m_spawnData;};
    virtual Vector2df getCenter() const;
    virtual Vector2df getScreenCenter() const;

    // setters
    virtual void setSize(Vector2df newSize) {m_size = newSize;}
    virtual void setPosition(const Vector2df newPos) {m_position = newPos;};
    virtual void incPosition(const Vector2df incPos) {m_position += incPos;}
    virtual void setX(CRfloat newX) {m_position.x = newX;}
    virtual void incX(CRfloat incX) {m_position.x += incX;}
    virtual void setY(CRfloat newY) {m_position.y = newY;}
    virtual void incY(CRfloat incY) {m_position.y += incY;}
    virtual void setState(CRint newState) {m_state = newState;}
    void setLevel(Level *level) {m_level = level;}
    void assignSpawnData(SpawnUnitData* const data) {m_spawnData = data;};

    // collision
    virtual void hit(const SimpleDirection dir, BaseUnit* const player, CRstring parameter="")=0;  // Handles any hit occuring with another unit
    virtual void hitMap(MapData* const data, const CollisionObject* const obj)=0;   // Handles any collision with the map

    // movement
    void accelerate(const Vector2df& value, const Vector2df& max);    // Initialize an acceleration of the unit up to a certain maximum by 'value' amount per cycle
    void accelerateX(CRfloat val, CRfloat max);
    void accelerateY(CRfloat val, CRfloat max);
    Vector2df getAcceleration() const {return m_acceleration[0];};
    Vector2df getMaxAcceleration() const {return m_acceleration[1];};

    void stopRightThere(); // stops all movement and acceleration

    // framework
    virtual void render();
    virtual void updateScreenPosition(const Vector2df mapOffset);
    virtual void update();  // Updates the counter, acceleration and other stuff

    virtual void remove(); // This is a soft removal - it should trigger a removal animation, and once complete, set m_shouldBeRemoved
    bool readyToRemove() const {return m_shouldBeRemoved;}

    // unit/object pickup
    virtual void resetParent();
    virtual void setParent(BaseUnit *parent);
    virtual void resetChild();
    virtual void setChild(BaseUnit *parent);
    bool isCarryingChild() const {return m_child;}
    bool isBeingCarried() const {return m_parent;}

    // AI
    virtual void action(BaseUnit* player); // unit AI code here, target player, attack, etc.

    Vector2df m_velocity;
    CollisionObject m_collisionInfo;
protected:
    virtual void customUpdate() {}; // Is called when the internal counter reaches zero
    CountDown m_counter;            // Internal counter
    Vector2df m_position;
    Vector2df m_size;
    int m_direction;                // Stores the movement direction of the unit (non final implementation)
    Vector2df m_acceleration[2];    // Stores the acceleration
    Vector2df m_maxSpeed;           // The maximum movement speed of the unit (internal)
    AnimatedSprite* m_sprite;       // Pointer to the current active sprite which will be drawn
    BaseUnit* m_parent;
    BaseUnit* m_child;
    Level* m_level;                 // The Level to which this object belongs, this is a forward class declaration, including "Level.h" is required where used
    bool m_shouldBeRemoved;         // Set this when it is time to remove the object
    SpawnUnitData* m_spawnData;     // Information about the spawn (position, parameter, etc.)
    int m_state;
private:
    void init();
    static void countDownWrapper(void* obj)
    {
        BaseUnit* self = (BaseUnit*) obj;
        self->customUpdate();
    }

};

#endif // BASEUNIT_H

